package com.carl.zeus.server.system;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.carl.zeus.common.constant.BusinessCode;
import com.carl.zeus.common.constant.BusinessConstants;
import com.carl.zeus.common.constant.BusinessMsg;
import com.carl.zeus.common.util.BusinessMsgUtil;
import com.carl.zeus.config.shiro.ShiroService;
import com.carl.zeus.dao.system.SysRoleMapper;
import com.carl.zeus.dao.system.SysUserMapper;
import com.carl.zeus.dao.system.SysUserRoleMapper;
import com.carl.zeus.model.system.SysRole;
import com.carl.zeus.model.system.SysUser;
import com.carl.zeus.model.system.SysUserRole;
import com.carl.zeus.model.vo.FrontPage;
import com.carl.zeus.model.vo.UserOnlineBo;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zcm
 * @since 2017-02-10
 */
@Service
public class SysUserService extends ServiceImpl<SysUserMapper, SysUser> {

	@Autowired
	private SysUserMapper sysUserMapper;

	@Autowired
	private SysRoleMapper sysRoleMapper;

	@Autowired
	private SysUserRoleMapper sysUserRoleMapper;

	@Autowired
	@Lazy
	ShiroService shiroService;

	@Autowired
	private RedisSessionDAO redisSessionDAO;
	
	@Autowired
	private SessionManager sessionManager;

	/**
	 * 统计用户数量
	 * @return
	 */
	public Integer countUserList() {
		return sysUserMapper.selectCount(new EntityWrapper<>());
	}

	public List<SysUser> listAjax(int page, int limit, String key, String value) {
		List<SysUser> userList = sysUserMapper.selectPage(
				new Page<SysUser>(page, limit),
				new EntityWrapper<SysUser>().like(key, value));
		return userList;
	}

	public SysUser findByUsername(String username) {
		return sysUserMapper.findByUsername(username);
	}

	public SysUser findByUsernameAndPassword(String username, String password) {
		return sysUserMapper.findByUsernameAndPassword(username, password);
	}
	
	//获取在线session的page对象
	public Page<UserOnlineBo> getPagePlus(FrontPage<UserOnlineBo> frontPage) {
		// 因为我们是用redis实现了shiro的session的Dao,而且是采用了shiro+redis这个插件
		// 所以从spring容器中获取redisSessionDAO
		// 来获取session列表.
		Collection<Session> sessions = redisSessionDAO.getActiveSessions();
		Iterator<Session> it = sessions.iterator();
		List<UserOnlineBo> onlineUserList = new ArrayList<>();
		Page<UserOnlineBo> pageList = frontPage.getPagePlus();
		// 遍历session
		while (it != null && it.hasNext()) {
			// 这是shiro已经存入session的, 现在直接取就是了
			Session session = it.next();
			//标记为已提出的不加入在线列表
			if(session.getAttribute("kickout") == null? false:true) continue;
			UserOnlineBo onlineUser = getSessionBo (session);
			if(onlineUser != null){
				onlineUserList.add(onlineUser);
			}
		}
		// 再将List<UserOnlineBo>转换成mybatisPlus封装的page对象
		int page = frontPage.getPage() - 1;
		int rows = frontPage.getRows() - 1;
		int startIndex = page * rows;
		int endIndex = (page * rows) + rows;
		int size = onlineUserList.size();
		if (endIndex > size) {
			endIndex = size;
		}
		pageList.setRecords(onlineUserList.subList(startIndex, endIndex));
		pageList.setTotal(size);
		return pageList;
	}

	//根据sessionId执行强制退出
	public void kickout(Serializable sessionId){
		this.getSessionBysessionId(sessionId).setAttribute("kickout", true);
	}
	
	//根据sesisonid获取单个session对象
	private Session getSessionBysessionId(Serializable sessionId){
		Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(sessionId));
		return kickoutSession;
	}

	//从session中获取UserOnline对象
	private UserOnlineBo getSessionBo(Session session){
		//获取session登录信息。
		Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
		if(null == obj){
			return null;
		}
		//确保是 SimplePrincipalCollection对象。
		if(obj instanceof SimplePrincipalCollection){
			SimplePrincipalCollection spc = (SimplePrincipalCollection)obj;
			/**
			 * 获取用户登录的，@link SampleRealm.doGetAuthenticationInfo(...)方法中
			 * return new SimpleAuthenticationInfo(user,user.getPswd(), getName());的user 对象。
			 */
			obj = spc.getPrimaryPrincipal();
			if(null != obj && obj instanceof SysUser){
				//存储session + user 综合信息
				UserOnlineBo userBo = new UserOnlineBo((SysUser)obj);
				//最后一次和系统交互的时间
				userBo.setLastAccess(session.getLastAccessTime());
				//主机的ip地址
				userBo.setHost(session.getHost());
				//session ID
				userBo.setSessionId(session.getId().toString());
				//session最后一次与系统交互的时间
				userBo.setLastLoginTime(session.getLastAccessTime());
				//回话到期 ttl(ms)
				userBo.setTimeout(session.getTimeout());
				//session创建时间
				userBo.setStartTime(session.getStartTimestamp());
				//是否踢出
				userBo.setSessionStatus(false);
				return userBo;
			}
		}
		return null;
	}

	public SysUser selectUserRolesByUserId(Long userId) {
		if(userId != null){
			SysUser user = sysUserMapper.selectById(userId);
			StringBuilder sb = new StringBuilder();
			StringBuilder sb2 = new StringBuilder();
			//用户所对应的角色信息
			List<SysRole> roles = sysRoleMapper.selectUserRolesByUserId(userId);
			if(null != roles && !roles.isEmpty()){
				for (SysRole role : roles) {
					sb.append(role.getId()).append(",");
					sb2.append(role.getName()).append(",");
				}
				if(sb.length()>0){
					sb.deleteCharAt(sb.length()-1);
					user.setRoleIds(sb.toString());
				}
				if(sb2.length()>0){
					sb2.deleteCharAt(sb2.length()-1);
					user.setRoleNames(sb2.toString());
				}
			}
			return user;
		}
		return null;
	}

	public List<UserOnlineBo> getUserOnline(int page, int limit) {
		// 因为我们是用redis实现了shiro的session的Dao,而且是采用了shiro+redis这个插件
		// 所以从spring容器中获取redisSessionDAO,来获取session列表.
		Collection<Session> sessions = redisSessionDAO.getActiveSessions();
		Iterator<Session> it = sessions.iterator();
		List<UserOnlineBo> onlineUserList = new ArrayList<>();
		List<UserOnlineBo> userList = new ArrayList<>();
		// 遍历session
		while (it != null && it.hasNext()) {
			// 这是shiro已经存入session的, 现在直接取就是了
			Session session = it.next();
			//标记为已提出的不加入在线列表
			if (session.getAttribute("kickout") == null? false:true) continue;
			UserOnlineBo onlineUser = getSessionBo (session);
			if (onlineUser != null) {
				onlineUserList.add(onlineUser);
			}
		}
		// 再将List<UserOnlineBo>转换成mybatisPlus封装的page对象
		int startIndex = (page-1) * limit;
		int endIndex = ((page-1) * limit) + limit;
		int size = onlineUserList.size();
		if (endIndex > size) {
			endIndex = size;
		}
		userList.addAll(onlineUserList.subList(startIndex, endIndex));
		return userList;
	}

	public Integer getUserOnlineSize() {
		Collection<Session> sessions = redisSessionDAO.getActiveSessions();
		return sessions.size();
	}
	/**
	 * 用户状态失效
	 * @param userId	用户Id
	 * @return
	 * @throws Exception
	 */
	@Transactional
	public BusinessMsg updateUserStatus(Long userId) {
		try {
			//解除用户与角色绑定关系
			List<SysUserRole> userRoles = sysUserRoleMapper.selectUserRolesListByUserId(userId);
			if (null != userRoles && !userRoles.isEmpty()) {
				for (SysUserRole userRole : userRoles) {
					sysUserRoleMapper.deleteById(userRole.getId());
				}
			}
			//更改用户状态为1-失效
			Map<String, Object> params = new HashMap<>();
			params.put("status", BusinessConstants.SYS_USER_STATUS_0.getCode());
			params.put("id", userId);
			sysUserMapper.updateUserByStatus(params);

			// 清空用户权限缓存信息
			shiroService.clearAllCacheAuth();
		} catch (Exception e) {
			throw e;
		}finally {
		}
		return BusinessMsgUtil.returnCodeMessage(BusinessCode.GLOBAL_SUCCESS);
	}

	/**
	 * 批量用户状态失效
	 * @param userIds	用户Id
	 * @return
	 * @throws Exception
	 */
	public BusinessMsg updateUserBatchStatus(Long[] userIds) {
		try {
			if(null != userIds && userIds.length > 0){
				for (Long userId : userIds) {
					//解除用户与角色绑定关系
					List<SysUserRole> userRoles = sysUserRoleMapper.selectUserRolesListByUserId(userId);
					if (null != userRoles && !userRoles.isEmpty()) {
						for (SysUserRole userRole : userRoles) {
							sysUserRoleMapper.deleteById(userRole.getId());
						}
					}
					//更改用户状态为1-失效
					Map<String, Object> params = new HashMap<>();
					params.put("status", BusinessConstants.SYS_USER_STATUS_0.getCode());
					params.put("id", userId);
					sysUserMapper.updateUserByStatus(params);
				}

				// 清空用户权限缓存信息
				shiroService.clearAllCacheAuth();
			}
		} catch (Exception e) {
			throw e;
		}finally {
		}
		return BusinessMsgUtil.returnCodeMessage(BusinessCode.GLOBAL_SUCCESS);
	}

}
